package web

import (
	"fmt"
	"gitee.com/tools/internal/service"
	"gitee.com/tools/internal/web/tools/common"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

type Encrypt struct {
	svc service.Encrypt
}

func NewEncrypt(svc service.Encrypt) *Encrypt {
	return &Encrypt{
		svc: svc,
	}
}

func (e *Encrypt) Router(r *gin.Engine) {
	g := r.Group("/encrypt")
	// 生成随机salt
	g.GET("/generate", e.generate)
	g.GET("/generateAes", e.generateAesKey)
	g.POST("/md5", e.md5)
	g.POST("/md5file", e.md5file)
	g.POST("/bcrypt", e.bcrypt)
	g.POST("/base64plus", e.base64Puls)
	g.POST("/base64", e.base64)
	g.POST("/urlencode", e.urlEncode)
	g.POST("/urluncode", e.urlUncode)
	g.POST("/aesencode", e.aesEncode)
	g.POST("/aesuncode", e.aesUncode)
	g.POST("/phpencrypt", e.phpjm)
	g.POST("/shaencrypt", e.shaEncrypt)
}

func (e *Encrypt) md5(ctx *gin.Context) {
	type Req struct {
		Password string `json:"password"`
		Salt     string `json:"salt"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}

	val, err := e.svc.Md5Salt(ctx, req.Password, req.Salt)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrEncryptMd5,
			Message: "加密失败",
		})
		return
	}
	log.Println(val)
	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "加密成功",
		Data: map[string]string{
			"md5": val,
		},
	})
	return
}

func (e *Encrypt) md5file(ctx *gin.Context) {
	file, header, err := ctx.Request.FormFile("file")
	defer file.Close()
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}

	filepath, err := UploadPath("encryptfile", header.Filename, file)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrFileSave,
			Message: "系统错误",
		})
		return
	}
	md5Val, err := e.svc.Md5File(ctx, filepath)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrEncryptMd5,
			Message: "获取文件的md5值失败",
		})

	} else {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    0,
			Message: "获取文件的md5值成功",
			Data: map[string]string{
				"type": strings.Split(header.Filename, ".")[len(strings.Split(header.Filename, "."))-1],
				"file": header.Filename,
				"md5":  md5Val,
			},
		})
	}
	err = os.Remove(filepath)
	if err != nil {
		// 重试
		return
	}

	return
}

func (e *Encrypt) bcrypt(ctx *gin.Context) {
	type Req struct {
		Pass string `json:"pass"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}

	val, err := e.svc.Bcrypt(ctx, req.Pass)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrEncryptBcrypt,
			Message: "加密失败",
		})
		return
	}

	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "加密成功",
		Data: map[string]string{
			"value": val,
		},
	})
	return
}

func (e *Encrypt) generate(ctx *gin.Context) {
	common.GenerateSalt(8)
	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "",
		Data:    nil,
	})
}

func (e *Encrypt) base64Puls(ctx *gin.Context) {
	type Req struct {
		Data string `json:"data"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}

	val, err := e.svc.Base64Plus(ctx, req.Data)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrBase64Encode,
			Message: "base64加密失败",
		})
		return
	}
	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "base64加密成功",
		Data: map[string]string{
			"base64": val,
		},
	})
	return
}

func (e *Encrypt) base64(ctx *gin.Context) {
	type Req struct {
		Data string `json:"data"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}

	val, err := e.svc.Base64(ctx, req.Data)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrBase64Uncode,
			Message: "base64解密失败",
		})
		return
	}
	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "base64解密成功",
		Data: map[string]string{
			"base64": val,
		},
	})
	return
}

func (e *Encrypt) urlEncode(ctx *gin.Context) {
	type Req struct {
		Data string `json:"data"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}
	val, err := e.svc.UrlEncode(ctx, req.Data)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrUrlEncode,
			Message: "url加密失败",
		})
		return
	}
	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "url加密成功",
		Data: map[string]string{
			"url": val,
		},
	})
	return
}

func (e *Encrypt) urlUncode(ctx *gin.Context) {
	type Req struct {
		Data string `json:"data"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}
	val, err := e.svc.UrlUncode(ctx, req.Data)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrUrlUncode,
			Message: "url解密失败",
		})
		return
	}

	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "url解密成功",
		Data: map[string]string{
			"url": val,
		},
	})
	return
}

func (e *Encrypt) generateAesKey(ctx *gin.Context) {
	length, err := strconv.Atoi(ctx.Query("length"))
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}
	val, err := common.GenerateAESKey(length)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrGenerateAesKey,
			Message: "生成AES密钥失败",
		})
		return
	}

	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "生成AES密钥成功",
		Data: map[string]string{
			fmt.Sprintf("AES-%d", length): string(val),
		},
	})
	return
}

func (e *Encrypt) aesEncode(ctx *gin.Context) {
	type Req struct {
		Plaintext   string `json:"plaintext"`
		Mode        string `json:"mode"`
		PaddingMode string `json:"paddingMode"`
		Length      int    `json:"length"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}
	key, err := common.GenerateAESKey(req.Length)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrGenerateAesKey,
			Message: "系统错误",
		})
		return
	}
	val, err := e.svc.AesEncode(ctx, req.Plaintext, req.Mode, req.PaddingMode, key)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrAESEncode,
			Message: "aes加密失败",
			Data:    nil,
		})
		return
	}

	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "aes加密成功",
		Data: map[string]any{
			"result":      val,
			"key":         key,
			"mode":        req.Mode,
			"paddingMode": req.PaddingMode,
		},
	})
}

func (e *Encrypt) aesUncode(ctx *gin.Context) {
	type Req struct {
		Plaintext   []byte `json:"plaintext"`
		Mode        string `json:"mode"`
		PaddingMode string `json:"paddingMode"`
		Key         []byte `json:"key"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}

	val, err := e.svc.AesUncode(ctx, req.Plaintext, req.Mode, req.PaddingMode, req.Key)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrAESUncode,
			Message: "aes解密失败",
			Data:    nil,
		})
		return
	}

	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "aes解密成功",
		Data: map[string]any{
			"result":      val,
			"key":         req.Key,
			"mode":        req.Mode,
			"paddingMode": req.PaddingMode,
		},
	})
	return
}

func (e *Encrypt) phpjm(ctx *gin.Context) {
	file, m, err := ctx.Request.FormFile("phpfile")
	defer file.Close()
	path, err := UploadPath("phpfile", m.Filename, file)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}
	data, err := os.ReadFile(path)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrFileRead,
			Message: "系统错误",
		})
		return
	}

	key, err := common.GenerateAESKey(16)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrGenerateAesKey,
			Message: "系统错误",
		})
		return
	}
	val, err := e.svc.ObfuscatePHPCode(ctx, string(data), key)
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrPhpCodeEncode,
			Message: "系统错误",
		})
		return
	}

	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: "代码混淆加密成功",
		Data: map[string]any{
			"code": val,
			"key":  key,
		},
	})
	err = os.Remove(path)
	if err != nil {
		//重试
		return
	}
	return
}

func (e *Encrypt) shaEncrypt(ctx *gin.Context) {
	type Req struct {
		Data        string `json:"data"`
		EncryptType string `json:"encryptType"`
	}
	var req Req
	if err := ctx.BindJSON(&req); err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrorUserInputInvalid,
			Message: "参数无效",
		})
		return
	}

	val, err := e.svc.ShaEncrypt(ctx, req.EncryptType, []byte(req.Data))
	if err != nil {
		ctx.JSON(http.StatusOK, common.Result{
			Code:    common.ErrSHAEncrypt,
			Message: fmt.Sprintf("%s加密失败", req.EncryptType),
		})
		return
	}

	ctx.JSON(http.StatusOK, common.Result{
		Code:    0,
		Message: fmt.Sprintf("%s加密成功", req.EncryptType),
		Data: map[string]any{
			"type":   req.EncryptType,
			"result": val,
		},
	})
	return
}
